package io.renren.modules.iots.utils.socket.client;

import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @ClassName: SingleSocketClientThread
 * @Description: 单例模式SocketClientThread类
 * @author 周西栋
 * @date 2018年5月8日
 *
 */
public class SingleSocketClientThread implements Runnable {
	
	/**
	 * 日志
	 */
	private Logger logger = LoggerFactory.getLogger(getClass());
	
	/************************************************      单例模式     ************************************************/
	
    /**
     * 创建一个新的实例 SingleSocketClientThread.
     */
    private SingleSocketClientThread() {
    	new Thread(this).start();
    }
    
    /**
     * 私有对象变量
     */
    private static final SingleSocketClientThread single = new SingleSocketClientThread();
    
    /**
     * @Title: getInstance
     * @Description: 饿汉模式--单例（静态工厂方法） 
     * @param @return    参数
     * @return SingleSocketClientThread    返回类型
     * @throws
     */
    public static SingleSocketClientThread getInstance() {
        return single;
    }
	
	/************************************************      单例模式     ************************************************/
	
    /**
     * 循环体
     */
    private Map<String,SocketBean> loop = new HashMap<>();
    
    
    
	@Override
	public void run() {
		logger.info("我启动了一个Socket链接的线程");
        try {
            // 轮询访问selector
            while (true) {
            	try {
					Thread.sleep(5000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
            	loop = SocketUtils.SOCKETBEAN_MAP;
            	if(!loop.isEmpty()){
            		Iterator<String> iter = loop.keySet().iterator();
        			while(iter.hasNext()){
        			    String keystr = iter.next();
        			    SocketBean socketBean = loop.get(keystr);
        			    // 地址
        			    String address = socketBean.getServerip()+":"+socketBean.getServerport();
        			    SelectionKey key = socketBean.getSelectionKey();
            			Selector selector = socketBean.getSelector();
            			//如果队列有新的Channel加入，那么Selector.select()会被唤醒
            			selector.select(1);//设置超时时间
            			if(key.isConnectable() && socketBean.getConnectstatus() != 4){
            				SocketChannel channel = socketBean.getSocketChannel();
                            // 如果正在连接，则完成连接
                            if (channel.isConnectionPending()) {
                            	logger.info(address+"正在尝试连接");
                            	socketBean.setConnectstatus(socketBean.getConnectstatus()==1?2:socketBean.getConnectstatus());
                                try {
                                	channel.finishConnect();
                                	logger.info(address+"已经连上了");
    							} catch (Exception e) {
    								socketBean.initialize();
    							}
                            }
                            if (channel.isConnected()) {
                            	deleteInoperationElement(address);
                            	socketBean.setConnectstatus(3);
    							// 设置成非阻塞
    							channel.configureBlocking(false);
    							//在和服务端连接成功之后，为了可以接收到服务端的信息，需要给通道设置读的权限。
    							channel.register(socketBean.getSelector(), SelectionKey.OP_READ);
    						}
            			}else if(key.isReadable() && socketBean.getConnectstatus() != 3){
            				SocketChannel channel = socketBean.getSocketChannel();
            				channel.close();
            				key.cancel();
            				logger.info(address+"已经断开，正在重连");
            				socketBean.setConnectstatus(2);
            				socketBean.initialize();
            			}
        			}
            	}
            }
        } catch (IOException e) {//IOException | ParseException e
            e.printStackTrace();
        } 
	}
	
	/**
	 * @Title: deleteInoperationElement
	 * @Description: 删除INOPERATION_SOCKETBEAN_MAP的元素
	 * @param @param key
	 * @param @return    参数
	 * @return boolean    返回类型
	 * @throws
	 */
	private boolean deleteInoperationElement(String key){
		try {
			Iterator<String> iter = SocketUtils.INOPERATION_SOCKETBEAN_MAP.keySet().iterator();
			while(iter.hasNext()){
			    String keystr = iter.next();
			    if(key.equals(keystr)){
			        iter.remove();
			    }
			}
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
}